package com.micro.ai.auth.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.micro.ai.auth.dto.*;
import com.micro.ai.auth.entity.Menu;
import com.micro.ai.auth.entity.Role;
import com.micro.ai.auth.entity.RoleMenu;
import com.micro.ai.auth.entity.User;
import com.micro.ai.auth.mapper.MenuMapper;
import com.micro.ai.auth.mapper.RoleMapper;
import com.micro.ai.auth.mapper.RoleMenuMapper;
import com.micro.ai.auth.mapper.UserMapper;
import com.micro.ai.auth.service.CaptchaService;
import com.micro.ai.auth.service.SmsService;
import com.micro.ai.auth.service.UserService;
import com.micro.ai.commons.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户服务实现
 * 
 * @author micro-ai
 * @since 0.0.1
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private RoleMenuMapper roleMenuMapper;

    @Autowired
    private CaptchaService captchaService;

    @Autowired
    private SmsService smsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    @Transactional
    public UserDTO register(UserRegisterRequest request) {
        try {
            // 1. 验证验证码
            if (request.getCaptchaCode() != null && request.getCaptchaKey() != null && StringUtils.hasText(request.getCaptchaKey())&& StringUtils.hasText(request.getCaptchaCode())) {
                if (!captchaService.validateCaptcha(request.getCaptchaKey(), request.getCaptchaCode())) {
                    throw new BusinessException("A0009", "验证码错误或已过期");
                }
            }

            // 2. 验证密码确认
            if (!request.getPassword().equals(request.getConfirmPassword())) {
                throw new BusinessException("A0010", "两次输入的密码不一致");
            }

            // 3. 检查用户名是否已存在
            User existingUser = userMapper.selectByTenantAndUsername(request.getTenantId(), request.getUsername());
            if (existingUser != null) {
                throw new BusinessException("A0011", "用户名已存在");
            }

            // 4. 检查邮箱是否已存在
            User existingEmail = userMapper.selectByTenantAndEmail(request.getTenantId(), request.getEmail());
            if (existingEmail != null) {
                throw new BusinessException("A0012", "邮箱已被注册");
            }

            // 5. 创建用户
            User user = new User();
            user.setId("usr_" + System.currentTimeMillis());
            user.setTenantId(request.getTenantId());
            user.setUsername(request.getUsername());
            user.setEmail(request.getEmail());
            user.setPasswordHash(passwordEncoder.encode(request.getPassword()));
            user.setDisplayName(request.getDisplayName() != null ? request.getDisplayName() : request.getUsername());
            user.setPhone(request.getPhone());
            user.setStatus("active");
            user.setCreatedAt(LocalDateTime.now());
            user.setUpdatedAt(LocalDateTime.now());

            userMapper.insert(user);

            // 6. 分配默认角色（普通用户）
            // TODO: 根据租户配置分配角色

            // 7. 构建用户DTO
            UserDTO userDTO = buildUserDTO(user);

            log.info("用户注册成功: userId={}, username={}", user.getId(), user.getUsername());
            return userDTO;

        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("用户注册失败", e);
            throw new BusinessException("B0001", "注册失败，请稍后再试");
        }
    }

    @Override
    @Transactional
    public UserDTO createUser(UserCreateRequest request) {
        try {
            // 1. 验证密码确认
            if (!request.getPassword().equals(request.getConfirmPassword())) {
                throw new BusinessException("A0010", "两次输入的密码不一致");
            }

            // 2. 检查用户名是否已存在（租户内唯一）
            User existingUser = userMapper.selectByTenantAndUsername(request.getTenantId(), request.getUsername());
            if (existingUser != null) {
                throw new BusinessException("A0011", "用户名已存在");
            }

            // 3. 检查邮箱是否已存在（租户内唯一）
            User existingEmail = userMapper.selectByTenantAndEmail(request.getTenantId(), request.getEmail());
            if (existingEmail != null) {
                throw new BusinessException("A0012", "邮箱已被注册");
            }

            // 4. 创建用户实体
            User user = new User();
            user.setId("usr_" + System.currentTimeMillis() + "_" + new Random().nextInt(1000));
            user.setTenantId(request.getTenantId());
            user.setUsername(request.getUsername());
            user.setEmail(request.getEmail());
            user.setPasswordHash(passwordEncoder.encode(request.getPassword()));
            user.setDisplayName(request.getDisplayName() != null ? request.getDisplayName() : request.getUsername());
            user.setPhone(request.getPhone());
            user.setAvatarUrl(request.getAvatarUrl());
            
            // 设置性别，默认为 unknown
            if (request.getGender() != null) {
                user.setGender(request.getGender());
            } else {
                user.setGender("unknown");
            }
            
            // 设置状态，默认为 active
            if (request.getStatus() != null) {
                user.setStatus(request.getStatus());
            } else {
                user.setStatus("active");
            }
            
            // 设置语言区域，默认为 zh-CN
            if (request.getLocale() != null) {
                user.setLocale(request.getLocale());
            } else {
                user.setLocale("zh-CN");
            }
            
            // 设置时区，默认为 Asia/Shanghai
            if (request.getTimezone() != null) {
                user.setTimezone(request.getTimezone());
            } else {
                user.setTimezone("Asia/Shanghai");
            }
            
            user.setCreatedAt(LocalDateTime.now());
            user.setUpdatedAt(LocalDateTime.now());

            // 5. 保存用户
            userMapper.insert(user);

            // 6. 构建用户DTO
            UserDTO userDTO = buildUserDTO(user);

            log.info("管理员创建用户成功: userId={}, username={}, tenantId={}", 
                user.getId(), user.getUsername(), user.getTenantId());
            return userDTO;

        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("管理员创建用户失败: username={}", request.getUsername(), e);
            throw new BusinessException("B0001", "创建用户失败，请稍后再试");
        }
    }

    @Override
    public UserDTO getCurrentUser(String userId) {
        try {
            User user = userMapper.selectById(userId);
            if (user == null) {
                throw new BusinessException("A0002", "用户不存在");
            }

            return buildUserDTO(user);

        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("获取用户信息失败: userId={}", userId, e);
            throw new BusinessException("B0001", "获取用户信息失败");
        }
    }

    @Override
    @Transactional
    public UserDTO updateUser(String userId, UserUpdateRequest request) {
        try {
            User user = userMapper.selectById(userId);
            if (user == null) {
                throw new BusinessException("A0002", "用户不存在");
            }

            // 更新用户信息
            if (request.getDisplayName() != null) {
                user.setDisplayName(request.getDisplayName());
            }
            if (request.getEmail() != null) {
                // 检查邮箱是否已被其他用户使用
                User existingEmail = userMapper.selectByTenantAndEmail(user.getTenantId(), request.getEmail());
                if (existingEmail != null && !existingEmail.getId().equals(userId)) {
                    throw new BusinessException("A0012", "邮箱已被其他用户使用");
                }
                user.setEmail(request.getEmail());
            }
            if (request.getPhone() != null) {
                user.setPhone(request.getPhone());
            }
            if (request.getAvatarUrl() != null) {
                user.setAvatarUrl(request.getAvatarUrl());
            }
            if (request.getGender() != null) {
                user.setGender(request.getGender());
            }
            if (request.getLocale() != null) {
                user.setLocale(request.getLocale());
            }
            if (request.getTimezone() != null) {
                user.setTimezone(request.getTimezone());
            }

            user.setUpdatedAt(LocalDateTime.now());
            userMapper.updateById(user);

            log.info("用户信息更新成功: userId={}", userId);
            return buildUserDTO(user);

        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("更新用户信息失败: userId={}", userId, e);
            throw new BusinessException("B0001", "更新用户信息失败");
        }
    }

    @Override
    @Transactional
    public boolean changePassword(String userId, PasswordChangeRequest request) {
        try {
            User user = userMapper.selectById(userId);
            if (user == null) {
                throw new BusinessException("A0002", "用户不存在");
            }

            // 验证当前密码
            if (!passwordEncoder.matches(request.getCurrentPassword(), user.getPasswordHash())) {
                throw new BusinessException("A0013", "当前密码错误");
            }

            // 验证新密码确认
            if (!request.getNewPassword().equals(request.getConfirmNewPassword())) {
                throw new BusinessException("A0010", "两次输入的新密码不一致");
            }

            // 更新密码
            user.setPasswordHash(passwordEncoder.encode(request.getNewPassword()));
            user.setUpdatedAt(LocalDateTime.now());
            userMapper.updateById(user);

            log.info("用户密码修改成功: userId={}", userId);
            return true;

        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("修改密码失败: userId={}", userId, e);
            throw new BusinessException("B0001", "修改密码失败");
        }
    }

    @Override
    @Transactional
    public boolean resetPassword(String phone, String smsCode, String newPassword) {
        try {
            // 1. 验证短信验证码
            if (!smsService.validateSmsCode(phone, smsCode)) {
                throw new BusinessException("A0014", "短信验证码错误或已过期");
            }

            // 2. 查找用户
            User user = userMapper.selectByPhone(phone);
            if (user == null) {
                throw new BusinessException("A0002", "用户不存在");
            }

            // 3. 更新密码
            user.setPasswordHash(passwordEncoder.encode(newPassword));
            user.setUpdatedAt(LocalDateTime.now());
            userMapper.updateById(user);

            log.info("用户密码重置成功: phone={}", phone);
            return true;

        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("重置密码失败: phone={}", phone, e);
            throw new BusinessException("B0001", "重置密码失败");
        }
    }

    /**
     * 构建用户DTO
     */
    private UserDTO buildUserDTO(User user) {
        // 查询用户角色
        List<Role> roles = roleMapper.selectByUserId(user.getId());
        List<String> roleCodes = roles.stream()
                .map(Role::getCode)
                .collect(Collectors.toList());

        // 查询用户的菜单权限
        List<String> permissionCodes = buildMenuButtonPermissions(user.getId());

        return UserDTO.builder()
                .id(user.getId())
                .tenantId(user.getTenantId())
                .username(user.getUsername())
                .email(user.getEmail())
                .displayName(user.getDisplayName())
                .avatarUrl(user.getAvatarUrl())
                .phone(user.getPhone())
                .gender(user.getGender())
                .locale(user.getLocale())
                .timezone(user.getTimezone())
                .status(user.getStatus())
                .roles(roleCodes)
                .permissions(permissionCodes)
                .createdAt(user.getCreatedAt() != null ? user.getCreatedAt().toString() : null)
                .updatedAt(user.getUpdatedAt() != null ? user.getUpdatedAt().toString() : null)
                .build();
    }

    @Override
    @Transactional
    public void assignRoles(String userId, List<String> roleIds) {
        // 验证用户存在
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException("A0001", "用户不存在");
        }

        // 删除用户现有角色（使用userRoleMapper）
        userMapper.deleteUserRoles(userId);

        // 分配新角色
        if (roleIds != null && !roleIds.isEmpty()) {
            // 验证所有角色都存在
            for (String roleId : roleIds) {
                Role role = roleMapper.selectById(roleId);
                if (role == null) {
                    throw new BusinessException("A0002", "角色不存在: " + roleId);
                }
            }
            // 批量插入用户角色
            userMapper.insertUserRoles(userId, roleIds);
        }

        log.info("为用户分配角色成功: userId={}, roleCount={}", userId, roleIds != null ? roleIds.size() : 0);
    }

    @Override
    @Transactional
    public void removeRoles(String userId, List<String> roleIds) {
        // 验证用户存在
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException("A0001", "用户不存在");
        }

        if (roleIds == null || roleIds.isEmpty()) {
            return;
        }

        // 移除指定角色
        userMapper.deleteUserRolesByRoleIds(userId, roleIds);

        log.info("移除用户角色成功: userId={}, roleCount={}", userId, roleIds.size());
    }

    @Override
    public Page<UserDTO> listUsers(int pageNum, int pageSize, String tenantId, String keyword, String status) {
        Page<User> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<User> query = new LambdaQueryWrapper<>();

        if (StringUtils.hasText(tenantId)) {
            query.eq(User::getTenantId, tenantId);
        }
        if (StringUtils.hasText(keyword)) {
            query.and(q -> q.like(User::getUsername, keyword)
                    .or().like(User::getEmail, keyword)
                    .or().like(User::getDisplayName, keyword)
                    .or().like(User::getPhone, keyword));
        }
        if (StringUtils.hasText(status)) {
            query.eq(User::getStatus, status);
        }

        query.orderByDesc(User::getCreatedAt);

        Page<User> userPage = userMapper.selectPage(page, query);

        Page<UserDTO> dtoPage = new Page<>(userPage.getCurrent(), userPage.getSize(), userPage.getTotal());
        dtoPage.setRecords(userPage.getRecords().stream()
                .map(this::buildUserDTO)
                .collect(Collectors.toList()));

        return dtoPage;
    }

    @Override
    public UserDTO getUserById(String userId) {
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException("A0001", "用户不存在");
        }
        return buildUserDTO(user);
    }

    @Override
    @Transactional
    public void updateUserStatus(String userId, String status) {
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException("A0001", "用户不存在");
        }

        user.setStatus(status);
        user.setUpdatedAt(LocalDateTime.now());
        userMapper.updateById(user);

        log.info("用户状态更新成功: userId={}, status={}", userId, status);
    }

    @Override
    @Transactional
    public void deleteUser(String userId) {
        // 1. 检查用户是否存在
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException("A0001", "用户不存在");
        }

        // 2. 删除用户的角色关联
        userMapper.deleteUserRoles(userId);

        // 3. 删除用户（硬删除，物理删除数据库记录）
        userMapper.deleteById(userId);

        log.info("用户删除成功: userId={}", userId);
    }
    
    /**
     * 构建用户的按钮权限列表
     * 只提取 type='button' 的菜单作为权限
     * 格式：button_code
     * 例如：["user:view", "user:create", "role:update", "menu:delete"]
     * 
     * @param userId 用户ID
     * @return 权限编码列表（按钮权限编码列表）
     */
    private List<String> buildMenuButtonPermissions(String userId) {
        List<String> permissions = new ArrayList<>();
        
        try {
            // 1. 查询用户的所有角色菜单关联
            List<RoleMenu> roleMenus = roleMenuMapper.selectByUserId(userId);
            
            if (roleMenus == null || roleMenus.isEmpty()) {
                return permissions;
            }
            
            // 2. 收集所有菜单ID（去重）
            Set<String> menuIds = roleMenus.stream()
                    .map(RoleMenu::getMenuId)
                    .collect(Collectors.toSet());
            
            // 3. 批量查询菜单信息
            if (!menuIds.isEmpty()) {
                List<Menu> menus = menuMapper.selectBatchIds(new ArrayList<>(menuIds));
                
                // 4. 只提取 type='button' 的菜单编码作为权限
                permissions = menus.stream()
                        .filter(menu -> "button".equals(menu.getType()))  // 只要按钮类型
                        .filter(menu -> menu.getCode() != null && !menu.getCode().isEmpty())
                        .map(Menu::getCode)
                        .distinct()
                        .collect(Collectors.toList());
            }
            
            log.debug("用户 {} 的按钮权限: {}", userId, permissions);
            
        } catch (Exception e) {
            log.error("构建用户按钮权限失败: userId={}, error={}", userId, e.getMessage(), e);
        }
        
        return permissions;
    }
}
